﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Forms;

namespace MoteurAudio
{

    /* Cette classe représente un système audio global pour une application, elle devra 
     * être chargée en static et accessible de tout le projet.
     * 
     * MODULE :
     * canal 0 : accordeur 
     * canaux 1-10 : Lecture des notes/accords modules
     * canal 11 : module accordeur
     * canaux 12 à 20 : réservé pour les autre module
     * canaux 21 à 100 Lecteur tablature
     */
    public class SystemeAudio
    {

        public static int OUTPUTRATE;// Fréquence d'échantillonage en sortie
        public static int SPECTRUMSIZE; // Taille du spectre
        public static float SPECTRUMRANGE;
        public static float BINSIZE;


        public static FMOD.System systemAudio = null; // Définition du système audio

        public static FMOD.Sound[] sound = new FMOD.Sound[80];
        public static FMOD.Channel[] channel = new FMOD.Channel[80];
        public static FMOD.ChannelGroup groupChannelModule = null, groupChannelLecteur = null, groupMaster = null;

        public static FMOD.DSP[] dsp = new FMOD.DSP[80];

        public static int outputfreq = 0;
        public static int bin = 0;
        public  enum langageNotation { Fr, En };



        /************* Gestion des drivers ************/
        public static int numdrivers = 0;
        public static uint version = 0;
        public static FMOD.RESULT resultat = FMOD.RESULT.OK;//  gestion des résultats d'erreur
        public static StringBuilder drivername = new StringBuilder(256);
        public static FMOD.GUID guid = new FMOD.GUID();


        /************* gestion de l'enregistrement *****************/
        public static int selectedInterface = 0; // interface d'enregistrement
        public static FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO();
        public static FMOD.DSP_RESAMPLER resampler = FMOD.DSP_RESAMPLER.MAX;




        // Tableau des notes
        public static string[] note =
        {
            "C 0", "C# 0", "D 0", "Eb 0", "E 0", "F 0", "F# 0", "G 0", "G# 0", "A 0", "Bb 0", "B 0",  
            "C 1", "C# 1", "D 1", "Eb 1", "E 1", "F 1", "F# 1", "G 1", "G# 1", "A 1", "Bb 1", "B 1",  
            "C 2", "C# 2", "D 2", "Eb 2", "E 2", "F 2", "F# 2", "G 2", "G# 2", "A 2", "Bb 2", "B 2",  
            "C 3", "C# 3", "D 3", "Eb 3", "E 3", "F 3", "F# 3", "G 3", "G# 3", "A 3", "Bb 3", "B 3",  
            "C 4", "C# 4", "D 4", "Eb 4", "E 4", "F 4", "F# 4", "G 4", "G# 4", "A 4", "Bb 4", "B 4",  
            "C 5", "C# 5", "D 5", "Eb 5", "E 5", "F 5", "F# 5", "G 5", "G# 5", "A 5", "Bb 5", "B 5",  
            "C 6", "C# 6", "D 6", "Eb 6", "E 6", "F 6", "F# 6", "G 6", "G# 6", "A 6", "Bb 6", "B 6",  
            "C 7", "C# 7", "D 7", "Eb 7", "E 7", "F 7", "F# 7", "G 7", "G# 7", "A 7", "Bb 7", "B 7",  
            "C 8", "C# 8", "D 8", "Eb 8", "E 8", "F 8", "F# 8", "G 8", "G# 8", "A 8", "Bb 8", "B 8",  
            "C 9", "C# 9", "D 9", "Eb 9", "E 9", "F 9", "F# 9", "G 9", "G# 9", "A 9", "Bb 9", "B 9"
        };


        // Tableau des notes française
        public static string[] noteFR =
        {
            "Do 0", "Do# 0", "Ré 0", "MiB 0", "Mi 0", "Fa 0", "Fa# 0", "Sol 0", "Sol# 0", "La 0", "SiB 0", "Si 0",  
            "Do 1", "Do# 1", "Ré 1", "MiB 1", "Mi 1", "Fa 1", "Fa# 1", "Sol 1", "Sol# 1", "La 1", "SiB 1", "Si 1",  
            "Do 2", "Do# 2", "Ré 2", "MiB 2", "Mi 2", "Fa 2", "Fa# 2", "Sol 2", "Sol# 2", "La 2", "SiB 2", "Si 2",  
            "Do 3", "Do# 3", "Ré 3", "MiB 3", "Mi 3", "Fa 3", "Fa# 3", "Sol 3", "Sol# 3", "La 3", "SiB 3", "Si 3",  
            "Do 4", "Do# 4", "Ré 4", "MiB 4", "Mi 4", "Fa 4", "Fa# 4", "Sol 4", "Sol# 4", "La 4", "SiB 4", "Si 4",  
            "Do 5", "Do# 5", "Ré 5", "MiB 5", "Mi 5", "Fa 5", "Fa# 5", "Sol 5", "Sol# 5", "La 5", "SiB 5", "Si 5",  
            "Do 6", "Do# 6", "Ré 6", "MiB 6", "Mi 6", "Fa 6", "Fa# 6", "Sol 6", "Sol# 6", "La 6", "SiB 6", "Si 6",  
            "Do 7", "Do# 7", "Ré 7", "MiB 7", "Mi 7", "Fa 7", "Fa# 7", "Sol 7", "Sol# 7", "La 7", "SiB 7", "Si 7",  
            "Do 8", "Do# 8", "Ré 8", "MiB 8", "Mi 8", "Fa 8", "Fa# 8", "Sol 8", "Sol# 8", "La 8", "SiB 8", "Si 8",  
            "Do 9", "Do# 9", "Ré 9", "MiB 9", "Mi 9", "Fa 9", "Fa# 9", "Sol 9", "Sol# 9", "La 9", "SiB 9", "Si 9"
        };



        public static float[] notefreq =
        {
            16.35f,   17.32f,   18.35f,   19.45f,    20.60f,    21.83f,    23.12f,    24.50f,    25.96f,    27.50f,    29.14f,    30.87f, 
            32.70f,   34.65f,   36.71f,   38.89f,    41.20f,    43.65f,    46.25f,    49.00f,    51.91f,    55.00f,    58.27f,    61.74f, 
            65.41f,   69.30f,   73.42f,   77.78f,    82.41f,    87.31f,    92.50f,    98.00f,   103.83f,   110.00f,   116.54f,   123.47f, 
            130.81f,  138.59f,  146.83f,  155.56f,   164.81f,   174.61f,   185.00f,   196.00f,   207.65f,   220.00f,   233.08f,   246.94f, 
            261.63f,  277.18f,  293.66f,  311.13f,   329.63f,   349.23f,   369.99f,   392.00f,   415.30f,   440.00f,   466.16f,   493.88f, 
            523.25f,  554.37f,  587.33f,  622.25f,   659.26f,   698.46f,   739.99f,   783.99f,   830.61f,   880.00f,   932.33f,   987.77f, 
            1046.50f, 1108.73f, 1174.66f, 1244.51f,  1318.51f,  1396.91f,  1479.98f,  1567.98f,  1661.22f,  1760.00f,  1864.66f,  1975.53f, 
            2093.00f, 2217.46f, 2349.32f, 2489.02f,  2637.02f,  2793.83f,  2959.96f,  3135.96f,  3322.44f,  3520.00f,  3729.31f,  3951.07f, 
            4186.01f, 4434.92f, 4698.64f, 4978.03f,  5274.04f,  5587.65f,  5919.91f,  6271.92f,  6644.87f,  7040.00f,  7458.62f,  7902.13f, 
            8372.01f, 8869.84f, 9397.27f, 9956.06f, 10548.08f, 11175.30f, 11839.82f, 12543.85f, 13289.75f, 14080.00f, 14917.24f, 15804.26f
        };


        public SystemeAudio()
        {

            OUTPUTRATE = 48000; // Fréquence d'échantillonage en sortie
            SPECTRUMSIZE = 8192; // Taille du spectre
            SPECTRUMRANGE = ((float)OUTPUTRATE / 2.0f);     /* 0 to nyquist */
            BINSIZE = (SPECTRUMRANGE / (float)SPECTRUMSIZE);


            try
            {
                /* Création du système audio */
                resultat = FMOD.Factory.System_Create(ref systemAudio);
                erreurInfos(resultat);

                /* On vérifie que le système et la version de FFMOD soit bien reconnu */
                resultat = systemAudio.getVersion(ref version);
                erreurInfos(resultat);
                if (version < FMOD.VERSION.number)
                {
                    MessageBox.Show("Erreur!  Vous utilisez une vielle version de FMOD " + version.ToString("X") + ".  This program requires " + FMOD.VERSION.number.ToString("X") + ".");
                    // Application.Current.Shutdown();
                }


                // OPTION : si le système est non initialisé on le force en directSound
                resultat = systemAudio.setOutput(FMOD.OUTPUTTYPE.DSOUND);

                resultat = systemAudio.setDriver(0);

                if (resultat != FMOD.RESULT.OK)
                {
                    MessageBox.Show("Erreur périphérique de lecture audio par défaut introuvable");


                }


                /* périphérique enregistrement par défault */
                FMOD.DSP_RESAMPLER resampler = FMOD.DSP_RESAMPLER.MAX;
                int temp = 0;
                FMOD.SOUND_FORMAT format = FMOD.SOUND_FORMAT.PCM16;

                resultat = systemAudio.setSoftwareFormat(OUTPUTRATE, FMOD.SOUND_FORMAT.PCM16, 1,0, 0);
                erreurInfos(resultat);

                resultat = systemAudio.init(80, FMOD.INITFLAGS.NORMAL, (IntPtr)null);
                erreurInfos(resultat);

                resultat = systemAudio.getSoftwareFormat(ref outputfreq, ref format, ref temp, ref temp, ref resampler, ref temp);
                erreurInfos(resultat);

            }
            catch (Exception ex)
            {
                Console.WriteLine("[Exception] Dans SystemeAudio.cs (systemAudio())" + ex.Message);
            }

        }


        // Libére le système audio        
        public  void Dispose()
        {

            resultat = systemAudio.close();
            erreurInfos(resultat);
            resultat = systemAudio.release();
            erreurInfos(resultat);


        }



        public void creerCannaux()
        {
            resultat = systemAudio.createChannelGroup("Group Lecteur", ref groupChannelLecteur);
            erreurInfos(resultat);

            resultat = systemAudio.createChannelGroup("Group Module", ref groupChannelModule);
            erreurInfos(resultat);

            resultat = systemAudio.getMasterChannelGroup(ref groupMaster);
            erreurInfos(resultat);

            /*
               Ajout de tout les cannaux 
            */
            resultat = groupMaster.addGroup(groupChannelLecteur);
            erreurInfos(resultat);

            resultat = groupMaster.addGroup(groupChannelModule);
            erreurInfos(resultat);


            // on alloue tout les canaux aux groupes
            for (int count = 0; count < 80; count++)
            {

                // On réserve 20 canaux pour les modules
                if (count <= 20)
                {
                    resultat = channel[count].setChannelGroup(groupChannelModule);
                }
                else
                {
                    // On réserve Le reste pour le lecteur multipiste
                    resultat = channel[count].setChannelGroup(groupChannelLecteur);
                }

                erreurInfos(resultat); // on controle les erreur


            }
        }


        /* Méthode de gestion de erreurs */
        public static void erreurInfos(FMOD.RESULT result)
        {
            if (result != FMOD.RESULT.OK)
            {

                // MessageBox.Show("Audio erreur! " + result + " - " + FMOD.Error.String(result));
                Console.WriteLine("[Audio erreur ]! " + result + " - " + FMOD.Error.String(result));
            }
        }

    }
}
